package com.jingdun.sport.cash

import SOrder
import com.jingdun.sport.authority.SecurityChecker
import com.jingdun.sport.authority.Users
import com.jingdun.sport.bean.model.ApiResult
import com.jingdun.sport.common.util.PageParam
import com.jingdun.sport.data.environment.DataEnvironment
import com.jingdun.sport.data.environment.page
import com.jingdun.sport.pay.Bill
import com.jingdun.sport.pay.PayService
import com.jingdun.sport.security.service.YamiUser
import com.jingdun.sport.sporttype.SportTypeRelations
import com.losttemple.sql.language.operator.*
import com.losttemple.sql.language.reflection.allFields
import com.losttemple.sql.language.reflection.useAll
import io.swagger.annotations.ApiModel
import io.swagger.annotations.ApiModelProperty
import io.swagger.annotations.ApiOperation
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import java.util.*

class Deposit {
    var room: Int? = null
}

data class CashAmount(
        val amount: Long,
        val amountScale: Int = 100
)

enum class WithdrawStatus(private val status: Int) {
    /**
     * 已申请，未打款
     */
    APPLIED(0), PAID(1), LOCKED(2), REJECTED(3);

    fun value(): Int {
        return status
    }

    val applied: Boolean
        get() = status == APPLIED.value()

    val paid: Boolean
        get() = status == PAID.value()

    val locked: Boolean
        get() = status == LOCKED.value()

    val rejected: Boolean
        get() = status == REJECTED.value()
}

fun Int.toWithdrawStatus(): WithdrawStatus {
    return enumValues<WithdrawStatus>().first { it.value() == this }
}

@ApiModel(value = "提现参数")
class WithdrawParam {
    @ApiModelProperty(value = "收款账号")
    var beneficiaryAccount: String? = null

    @ApiModelProperty(value = "收款人姓名")
    var accountOwner: String? = null
}

@ApiModel(value = "打款参数")
class RemitParam {
    @ApiModelProperty(value = "提款申请id")
    val id: Long? = null

    @ApiModelProperty(value = "打款金额")
    val amount: Double? = null

    @ApiModelProperty(value = "备注")
    val note: String? = null
}

@RestController
@RequestMapping("/sport/cash/")
class CashController {
    @Autowired
    private lateinit var sql: DataEnvironment

    @Autowired
    private lateinit var payService: PayService

    @Autowired
    private lateinit var securityChecker: SecurityChecker

    private fun findRoomDeposit(roomId: Int): CashAmount {
        return CashAmount(100)
    }

    @PostMapping("/pay")
    fun payDeposit(@RequestBody deposit: Deposit): ResponseEntity<Any> {
        val apiResult: ApiResult<*> = ApiResult<Any?>()
        val depositAmount = findRoomDeposit(deposit.room!!)
        val bill = Bill().apply {
            subject = "Deposit"
            tradeNo = "0"
            amount = depositAmount.amount
            amountScale = depositAmount.amountScale
        }
        val result = payService.pay(bill)
        apiResult.data = result
        return ResponseEntity.ok(apiResult)
    }

    @PostMapping("/withdraws")
    @ApiOperation(value = "用户申请提现", notes = "用户申请提现")
    fun applyWithdraw(@RequestBody param: WithdrawParam): ResponseEntity<Any> {
        val yamiUser = securityChecker.user
        sql.run {
            val status = from { Withdrawals(it) }
                    .where { user eq yamiUser.userId }
                    .orderDesc { id }
                    .limit(1)
                    .use { need(it.status) }
                    .select { it.status()?.toWithdrawStatus() }
                    .firstOrNull()
            if (status != null) {
                if (status.applied || status.locked) {
                    return ResponseEntity.badRequest().body("Too many applications.")
                }
            }

            val now = Date()

            db { Withdrawals(it) }
                    .insert {
                        it.applyTime(now)
                        it.account(param.beneficiaryAccount)
                        it.accountOwner(param.accountOwner)
                        it.user(yamiUser.userId)
                        it.status(WithdrawStatus.APPLIED.value())
                    }()
            return ResponseEntity.ok("apply committed")
        }
    }


    private fun DataEnvironment.lockedAmount(userId: String): Double {
        return from { Withdrawals(it) }
                .where { user eq userId }
                .where { status eq WithdrawStatus.LOCKED.value() }
                .aggregate { sum { amount } }()!!
    }

    @PostMapping("/remittances")
    @ApiOperation(value = "打款", notes = "打款")
    fun remit(@RequestBody param: RemitParam): ResponseEntity<Any> {
        if (!securityChecker.hasAuthority("remit")) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
        }
        sql.run {
            val apply = from { Withdrawals(it) }
                    .where { id eq param.id!!.toInt() }
                    .limit(1)
                    .use {
                        need(it.status)
                        need(it.user)
                        need(it.amount)
                    }
                    .select {
                        object {
                            val status = it.status()!!.toWithdrawStatus()
                            val user = it.user()!!
                            val amount = it.amount()
                        }
                    }
                    .firstOrNull()
                    ?: return ResponseEntity.badRequest().body("Can't find the application.")
            val status = apply.status

            val money = from { Users(it) }
                    .where { id eq apply.user }
                    .use { need(it.money) }
                    .select { it.money() }
                    .firstOrNull()!!
            val amount = if (status.locked) {
                if (param.amount != null) {
                    return ResponseEntity.badRequest().body("Amount's not needed.")
                }
                apply.amount!!
            } else {
                if (!status.applied) {
                    return ResponseEntity.badRequest().body("Application's not in the correct status.")
                }
                if (param.amount!! > money - lockedAmount(apply.user)) {
                    return ResponseEntity.badRequest().body("Withdraw exceeds balance.")
                }
                param.amount
            }
            db { Withdrawals(it) }
                    .where { id eq param.id!!.toInt() }
                    .update {
                        it.status(WithdrawStatus.PAID.value())
                        it.note(param.note!!)
                        if (!status.locked) {
                            it.amount(param.amount!!)
                        }
                    }()
            db { Users(it) }
                    .where { id eq apply.user }
                    .update {
                        it.money(money - amount)
                    }()
            return ResponseEntity.ok("1")
        }
    }

    @PostMapping("/locks")
    @ApiOperation(value = "锁定打款申请", notes = "锁定打款申请")
    fun lockWithdraw(@RequestBody param: RemitParam): ResponseEntity<Any> {
        if (!securityChecker.hasAuthority("remit")) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
        }
        sql.run {
            val apply = from { Withdrawals(it) }
                    .where { id eq param.id!!.toInt() }
                    .limit(1)
                    .use {
                        need(it.status)
                        need(it.user)
                    }
                    .select {
                        object {
                            val status = it.status()!!.toWithdrawStatus()
                            val user = it.user()!!
                        }
                    }
                    .firstOrNull()
                    ?: return ResponseEntity.badRequest().body("Can't find the application.")
            if (!apply.status.applied) {
                return ResponseEntity.badRequest().body("Application's not in the correct status.")
            }
            val money = from { Users(it) }
                    .where { id eq apply.user }
                    .use { need(it.money) }
                    .select { it.money() }
                    .firstOrNull()!!
            val amount = if (param.amount == null) {
                money
            } else {
                if (param.amount > money - lockedAmount(apply.user)) {
                    return ResponseEntity.badRequest().body("Withdraw exceeds balance.")
                }
                param.amount
            }
            db { Withdrawals(it) }
                    .where { id eq param.id!!.toInt() }
                    .update {
                        it.status(WithdrawStatus.LOCKED.value())
                        it.amount(amount)
                    }()
            db { SOrder(it) }
                    .insert {
                        it.payAmount(amount)
                        it.gmtCreate(Date())
                        it.gmtCreate(Date())
                        it.hasPayed(1)
                        it.userId(apply.user)
                        it.payDetail("提现-提现支付宝")
                        it.type(0)
                    }()
            return ResponseEntity.ok("1")
        }
    }

    @GetMapping("/withdraws")
    @ApiOperation(value = "用户申请提现", notes = "用户申请提现")
    fun listWithdraw(param: PageParam<*>): ResponseEntity<Any> {
        if (!securityChecker.hasAuthority("remit")) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
        }
        val user = securityChecker.userEntity
        sql.run {
            val result = from { Withdrawals(it) }
                    .order { id }
                    .page(param)
                    .with(allFields())
                    .select {
                        object {
                            val id = it.id()
                            val applyTime = it.applyTime()
                            val account = it.account()
                            val accountOwner = it.accountOwner()
                            val user = it.user()
                            val status = it.status()
                            val amount = it.amount()
                            val note = it.note()
                        }
                    }
            return ResponseEntity.ok(result)
        }
    }

    @GetMapping("/withdraws/{id}")
    @ApiOperation(value = "用户申请提现", notes = "用户申请提现")
    fun listWithdraw(@PathVariable("id") id1: Int): ResponseEntity<Any> {
        if (!securityChecker.hasAuthority("remit")) {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build()
        }
        val user = securityChecker.userEntity
        sql.run {
            val result = from { Withdrawals(it) }
                    .where { id eq id1 }
                    .limit(1)
                    .useAll()
                    .select {
                        object {
                            val id = it.id()
                            val applyTime = it.applyTime()
                            val account = it.account()
                            val accountOwner = it.accountOwner()
                            val user = it.user()
                            val status = it.status()
                            val amount = it.amount()
                            val note = it.note()
                        }
                    }.firstOrNull()
            return ResponseEntity.ok(result)
        }
    }

    @GetMapping("/latest/withdraw")
    @ApiOperation(value = "最近的提现状态", notes = "最近的提现状态")
    fun latestWithdraw(): ResponseEntity<Any?> {
        val yamiUser: YamiUser = securityChecker.user
        sql.run {
            val result = from { Withdrawals(it) }
                    .where { user eq yamiUser.userId }
                    .orderDesc { id }
                    .limit(1)
                    .useAll()
                    .select {
                        object {
                            val id = it.id()
                            val applyTime = it.applyTime()
                            val account = it.account()
                            val accountOwner = it.accountOwner()
                            val user = it.user()
                            val status = it.status()
                            val amount = it.amount()
                            val note = it.note()
                        }
                    }.firstOrNull {
                        it.status == WithdrawStatus.APPLIED.value()
                    }
            return ResponseEntity.ok(result)
        }
    }
}